package org.streets.eis.ext.rbac.pages;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.link.AbstractLink;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.util.string.Strings;
import org.streets.commons.util.DigestUtils;
import org.streets.database.Limits;
import org.streets.database.SQLConnection;
import org.streets.eis.component.dropdown.ToolBar;
import org.streets.eis.component.foreigncombobox.ForeignDefinition;
import org.streets.eis.component.grid.EditFlagColumn;
import org.streets.eis.component.grid.EditableColumn;
import org.streets.eis.component.grid.ForeignComboBoxColumn;
import org.streets.eis.component.grid.TableList;
import org.streets.eis.component.grid.TableList.ExcelFile;
import org.streets.eis.component.messagebox.MessageBox;
import org.streets.eis.component.messagebox.MessageBox.ReturnType;
import org.streets.eis.component.model.DataModel;
import org.streets.eis.component.model.DefaultTableModel;
import org.streets.eis.component.model.MenuItem;
import org.streets.eis.ext.rbac.entities.Employee4Rbac;
import org.streets.eis.pages.BasePage;
import org.streets.eis.setting.validatior.TableListValidator;
import org.streets.eis.types.UnitType;

import com.inmethod.grid.IGridColumn;
import com.inmethod.grid.column.AbstractColumn;
import com.inmethod.grid.column.CheckBoxColumn;
import com.inmethod.grid.column.PropertyColumn;

public class UserListPage extends BasePage {
	@Inject
	private SQLConnection conn;
	
	private TableList<Employee4Rbac> employeeList; 
	
	private String employeeSql = "SELECT * FROM EIS_EMPLOYEE WHERE ORGAN_ID='%s' ";
	
	private String sql;
	
	private FeedbackPanel feedbackPanel; 
	
	private String organId;
	
	private String companyId;
	
	@SuppressWarnings("unchecked")
	public UserListPage(final String organId){
		super();
		
		this.organId = organId;
		employeeSql = String.format(employeeSql,organId);
		
		add(new Label("htmlTitle","员工列表"));
		
		feedbackPanel = new FeedbackPanel("feedback");	
		
		Form form = new Form("form"){
			private static final long serialVersionUID = 1L;
			protected void onError(){
				employeeList.onValidateError(feedbackPanel);
			}
		};
		
		add(form);
		
		form.add(feedbackPanel.setOutputMarkupId(true));
		form.add(employeeList=createEmployeeList("employeeList"));
		employeeList.setAllowSelectMultiple(true);	
		employeeList.setClickRowToSelect(true);
		employeeList.setShowFilterBar(true);

		form.add(createToolBar());
    }
	
	private ToolBar createToolBar(){
		DataModel<MenuItem> model = new DataModel<MenuItem>();
		model.addChild(new DataModel<MenuItem>(new MenuItem("post","post","保存修改")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("refresh","refresh","&nbsp;刷新&nbsp;")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("delete","delete","删除账户")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("saveAs","saveAs","导出员工账户列表")));
		
		return new ToolBar("toolbar",model){
			private static final long serialVersionUID = 1L;
			@Override
			protected boolean needFormSubmitted(MenuItem menuItem){
				return "post".equals(menuItem.getCode());
			}
			@Override
			protected void onMenuItemClicked(AbstractLink link,DataModel<MenuItem> dataModel,AjaxRequestTarget target){
				if ("delete".equals(dataModel.getObject().getCode())){
        			deleteSelected(target);
        		}
				if ("post".equals(dataModel.getObject().getCode())){
        			postIt(target);
        		}
				if ("refresh".equals(dataModel.getObject().getCode())){
					employeeList.cancelEditAllRows();
					employeeList.resetSelectedItems();
					target.addComponent(getPage());
        		}
				if ("saveAs".equals(dataModel.getObject().getCode())){
					saveAsExcel(target);
        		}				
        	}
        };
	}
	
	
	private TableList<Employee4Rbac> createEmployeeList(String id){
		return new TableList<Employee4Rbac>(id, new DefaultTableModel<Employee4Rbac>(){
			private static final long serialVersionUID = 1L;
			@Override
			public List<Employee4Rbac> getPageRecords(long offset,int limit,String sortProperty,boolean isAsc){
				String orderBy = (!Strings.isEmpty(sortProperty)) ? " ORDER BY " + sortProperty +(isAsc? " ASC" : " DESC") : "";
				StringBuffer where = new StringBuffer(" and (1=1 ");
				for (String filterSql : employeeList.getFilterSqls().values()){
					where.append(" and ").append(filterSql);
				}
				where.append(")");
				sql = employeeSql + where.toString() + orderBy;
				return conn.query(sql , Employee4Rbac.class,Limits.none());
			}
			@Override
			protected  long getRecordsCount(){
				return conn.count(sql);
			}
		}, generateEmployeeColumns()){
			private static final long serialVersionUID = 1L;
			@Override
			protected Employee4Rbac reloadRowObject(final Employee4Rbac curValue){
				return conn.unique(employeeSql + " AND ID=?",Employee4Rbac.class,new String[]{curValue.id});
			}
			@Override
			public String generateColumnFilterSql(IGridColumn column,FilterCondition condition){
				if ("POS_ID".equals(column.getSortProperty())) { 
					if (Strings.isEmpty(condition.operatorMode)){
						return " (POS_ID IN (SELECT ID FROM EIS_POSITION WHERE " + generateLikeSql("NAME",condition.value) + " ) ) ";
					} else {
						return " (POS_ID IN (SELECT ID FROM EIS_POSITION WHERE NAME " + condition.operatorMode + "'"+ condition.value + "' ) ) ";
					}
				} else {
					return super.generateColumnFilterSql(column, condition);
				}
			}
		}.add(new TableListValidator<Employee4Rbac>("unique.user.id","userId") {
			private static final long serialVersionUID = 1L;
			@Override
			public boolean doValidate(FormComponent<?>[] formComponents,Employee4Rbac object) {
				return conn.count("SELECT * FROM EIS_EMPLOYEE WHERE USER_ID=? AND ID<>?",new Object[]{formComponents[0].getInput(),object.id}) == 0;
			}
			@Override
			public boolean doValidate(	Map<Employee4Rbac, FormComponent<?>[]> editedRows) {
				List<String> tmp = new ArrayList<String>(editedRows.size());
				for (FormComponent<?>[] formComponents : editedRows.values()){
					String key = formComponents[0].getInput();
					if (tmp.contains(key)){
						return false;
					} else {
						tmp.add(key);
					}
				}
				return true;
			}
		});
	}
	
	private String getCompanyId(String organId){
		if (Strings.isEmpty(companyId)){
			String attrSql = String.format("(ATTR='%s' or ATTR='%s')",UnitType.GROUP.value(),UnitType.COMPANY.value());
			String sql = String.format("SELECT ID  FROM EIS_ORGAN WHERE %s START WITH ID = '%s'  CONNECT BY ID = prior PARENT_ID", attrSql,organId);
			List<String> list = conn.column(sql,Limits.none());
			if (list.size()>0){
				companyId = list.get(0);
			}
		} 
		return companyId;
	}
	
	private List<IGridColumn> generateEmployeeColumns(){
		List<IGridColumn> columns = new ArrayList<IGridColumn>();
		columns.add(new CheckBoxColumn("check"));
		columns.add(new EditFlagColumn("editFlag"));
		columns.add(new PropertyColumn(Model.of("员工姓名"), "name", "NAME").setInitialSize(85));
		String sqlCondition = String.format("VALID_TO>=sysdate and ORGAN_ID='%s'",getCompanyId(organId));
		ForeignDefinition foreignDef = new ForeignDefinition("ID","NAME","EIS_POSITION","NAME",sqlCondition);
		columns.add(new ForeignComboBoxColumn(Model.of("职位"), "position", "POS_ID", foreignDef){
			private static final long serialVersionUID = 1L;
			@SuppressWarnings("unchecked")
			@Override
			protected void addValidators(FormComponent component) {
				component.setRequired(true);
			}			
		}.setInitialSize(85));
		columns.add(new EditableColumn(Model.of("登陆账户"), "userId", "USER_ID"){
			private static final long serialVersionUID = 1L;
			@SuppressWarnings("unchecked")
			@Override
			protected void addValidators(FormComponent component) {
				component.setRequired(true);
			}
		});
		columns.add(new EditableColumn(Model.of("密码"), "password"){
			private static final long serialVersionUID = 1L;
			@SuppressWarnings("unchecked")
			@Override
			protected void addValidators(FormComponent component) {
				component.setRequired(true);
			}
			
			@SuppressWarnings("unchecked")
			@Override
			protected FormComponent newEditableComponent(String id, final IModel model, IModel rowModel, AbstractColumn column){
				return new PasswordTextField(id,model){
					private static final long serialVersionUID = 1L;

					@Override
					protected void onComponentTag(final ComponentTag tag){
						tag.put("type", "password");
						super.onComponentTag(tag);
					}
				}.setResetPassword(false);
			}
			
			@SuppressWarnings("unchecked")
			@Override
			protected IModel getFieldModel(IModel rowModel) {
				return new PropertyModel(rowModel, "editedPassword");
			}
		});
		columns.add(new EditableColumn(Model.of("用户级别"), "userLevel"));
		
		return columns;
	}
	

	@SuppressWarnings("unchecked")
	private void deleteSelected(AjaxRequestTarget target){
		if (employeeList.getSelectedItems().size()>0){
			getMessageBox().question("确定要删除所选员工的登陆账户吗？",new MessageBox.DialogCallback(){
				private static final long serialVersionUID = 1L;

				public void onDialogClosed(AjaxRequestTarget target,ReturnType result) {
					if (result == ReturnType.YES){						
						StringBuffer sqls = new StringBuffer();
						for (Iterator iterator = employeeList.getSelectedItems().iterator(); iterator.hasNext();) {
							IModel rowModel = (IModel) iterator.next();
							Employee4Rbac emp = (Employee4Rbac) (rowModel).getObject();
							sqls.append(String.format("UPDATE EIS_EMPLOYEE SET USER_ID=NULL WHERE ID='%s';",emp.id))
								.append(String.format("DELETE FROM EIS_USER WHERE USER_ID='%s';",emp.userId));
							employeeList.setItemEdit(rowModel, false);
						}
						conn.execute(sqls.toString());						
						employeeList.ajaxRefresh();
					}
				}
				
			});			
		} else {
			getMessageBox().error("请选择要删除账户的记录!");
		}
	}
	
	/**
	 * 里面有个偷懒的地方：如果密码长为32位表示没有修改密码，其他长度表示修改了密码需要md5加密
	 * @param target
	 */
	private void postIt(AjaxRequestTarget target){
		List<IModel<Employee4Rbac>> editedList = employeeList.getEditingRowModels();	
		StringBuffer sqls = new StringBuffer();
		if (editedList.size()>0){
			for (Iterator<IModel<Employee4Rbac>> iterator = editedList.iterator(); iterator.hasNext();) {
				IModel<Employee4Rbac> rowModel = iterator.next();
				Employee4Rbac emp = rowModel.getObject(); 
				String password = emp.getEditedPassword();
				if (password.length()!=32){
					password = DigestUtils.md5Hex(password);
				}				
				sqls.append(String.format("UPDATE EIS_EMPLOYEE SET USER_ID=NULL,POS_ID='%s' WHERE ID='%s';",emp.getPosition().getId(),emp.id))
					.append(String.format("DELETE FROM EIS_USER WHERE USER_ID='%s';",emp.user.getUid())) 
					.append(String.format("INSERT INTO  EIS_USER(USER_ID,PASS,USER_LEVEL) VALUES('%s','%s',%d);",emp.userId,password,emp.getUserLevel()))
					.append(String.format("UPDATE EIS_EMPLOYEE SET USER_ID='%s' WHERE ID='%s';",emp.userId,emp.id));
				employeeList.setItemEdit(rowModel, false);
			}
			conn.execute(sqls.toString());
			target.addComponent(feedbackPanel);
			employeeList.update();
		}
	}	
	
	private void saveAsExcel(AjaxRequestTarget target){
		employeeList.setCreateExcelCallback(new TableList.CreateExcelFileCallback(){
			private static final long serialVersionUID = 1L;
			public ExcelFile createExcel() {
				String fileName = String.format("员工账户列表-%s.xls",new SimpleDateFormat("yyyyMMdd").format(new Date()));
				List<IGridColumn> columns = new ArrayList<IGridColumn>();
				columns.addAll(employeeList.getAllColumns());
				for (int i = 0;i<columns.size();i++){
					if ("password".equalsIgnoreCase(columns.get(i).getId())){
						columns.remove(i);
						break;
					}
				}
				return employeeList.generateExcelFile(fileName,"员工账户列表",conn.query(sql , Employee4Rbac.class,Limits.none()),columns);
			}
		});	
		target.appendJavascript(employeeList.getSaveAsExcelJavascript());
	}	
}
